<!-- // src/views/EventFlowDemo.vue -->
<template>
    <div class="event-flow-demo">
        <h3>DOM事件流完整演示 - 捕获、目标、冒泡</h3>

        <!-- 事件流可视化 -->
        <div class="flow-diagram">
            <div class="phase capture-phase">
                <h4>1. 捕获阶段 (Capturing)</h4>
                <p>window → document → body → outer → inner</p>
            </div>

            <div class="phase target-phase">
                <h4>2. 目标阶段 (Target)</h4>
                <p>在目标元素上触发</p>
            </div>

            <div class="phase bubble-phase">
                <h4>3. 冒泡阶段 (Bubbling)</h4>
                <p>inner → outer → body → document → window</p>
            </div>
        </div>

        <!-- 事件监听器演示 -->
        <div class="demo-container">
            <div class="outer-box" ref="outerBox" @click="handleClick('outer')">
                <div class="inner-box" ref="innerBox" @click="handleClick('inner')">
                    点击我测试事件流
                </div>
            </div>
        </div>

        <!-- 控制面板 -->
        <div class="control-panel">
            <el-button @click="addEventListeners">添加事件监听器</el-button>
            <el-button @click="removeEventListeners">移除事件监听器</el-button>
            <el-button @click="testEventFlow">测试事件流</el-button>
            <el-button @click="clearLogs">清空日志</el-button>

            <el-checkbox v-model="useCapture" @change="reloadListeners">使用捕获阶段</el-checkbox>
            <el-checkbox v-model="stopPropagation" @change="reloadListeners">阻止冒泡</el-checkbox>
        </div>

        <!-- 日志输出 -->
        <div class="log-output">
            <h4>事件流日志：</h4>
            <div class="logs">
                <div v-for="(log, index) in eventLogs" :key="index" :class="['log-item', log.type]">
                    [{{ log.timestamp }}] {{ log.message }}
                </div>
            </div>
        </div>
        <div class="button" @click="test">
            <div class="icon add"></div>
            测试
        </div>
        <a href="https://www.baidu.com" @click="baidu">超链接</a>
    </div>
</template>

<script>
export default {
    name: 'EventFlowDemo',
    data() {
        return {
            eventLogs: [],
            useCapture: false,
            stopPropagation: false,
            listenersAdded: false
        }
    },
    mounted() {
        this.addEventListeners()
    },
    beforeUnmount() {
        this.removeEventListeners()
    },
    methods: {
        test() {
            // const returnData = this.test1();
            // console.log(333, returnData);
            try {
                this.test1(); // 触发错误
            } catch (error) {
                console.log("验证失败:", error, error.message); // 输出：验证失败: 用户名不能为空！
                this.$message(error.message); // 提示用户
            }
        },
        /**
         * @description return(false|true都可以中止，只是返回的不一样，还有一个区别就是针对默认行为,比如超链接，表单提交等等)
         */
        baidu() {
            console.log("我是超链接");
            const a = 1;
            if (a !== 1) {
                return false;
                //return false 是明确阻止默认行为的传统方式，但现代代码更推荐用 event.preventDefault()
            } else {
                console.log("继续跳转");
                // return 和 return true 在事件处理函数中效果相同（都允许默认行为）
                return;
            }
        },
        test1() {
            const a = 1;
            if (a == 1) {
                throw new Error("条件成立，终止执行！");
                // return true; // 直接退出函数
            }
            console.log("后续代码不会执行");
        },
        logEvent(message, type = 'info') {
            const timestamp = new Date().toLocaleTimeString()
            this.eventLogs.push({
                timestamp,
                message,
                type
            })
            // 限制日志数量
            if (this.eventLogs.length > 50) {
                this.eventLogs = this.eventLogs.slice(-50)
            }
        },

        // 添加原生事件监听器
        addEventListeners() {
            if (this.listenersAdded) return

            const options = this.useCapture ? { capture: true } : {};//false就空对象
            //第三个参数可以是布尔值或者对象（现在浏览器更推荐的用对象），默认false,也就是默认不会捕获
            // window.addEventListener('click', handler, true)  // 捕获阶段
            // window.addEventListener('click', handler, false) // 冒泡阶段（默认是冒泡的）
            // {
            //     capture: false,    // 是否在捕获阶段触发
            //     once: false,      // 是否只执行一次
            //     passive: false    // 是否被动监听（优化性能）
            // } 第三个参数完整选项
            // Window级别
            window.addEventListener('click', this.handleWindowClick, options)

            // Document级别  
            document.addEventListener('click', this.handleDocumentClick, options)

            // Body级别
            document.body.addEventListener('click', this.handleBodyClick, options)

            this.listenersAdded = true
            this.logEvent('✅ 已添加所有事件监听器', 'success')
        },

        // 移除事件监听器
        removeEventListeners() {
            if (!this.listenersAdded) return

            const options = this.useCapture ? { capture: true } : {}

            window.removeEventListener('click', this.handleWindowClick, options)
            document.removeEventListener('click', this.handleDocumentClick, options)
            document.body.removeEventListener('click', this.handleBodyClick, options)

            this.listenersAdded = false
            this.logEvent('❌ 已移除所有事件监听器', 'warning')
        },

        // 重新加载监听器
        reloadListeners() {
            this.removeEventListeners()
            setTimeout(() => this.addEventListeners(), 100)
        },

        // 各种事件处理函数
        handleWindowClick(event) {
            console.log('这是handleWindowClick');
            this.logEvent(`🌐 Window捕获事件 - phase: ${event.eventPhase}`, 'capture')
        },

        handleDocumentClick(event) {
            console.log('这是handleDocumentClick',e);
            this.logEvent(`📄 Document捕获事件 - phase: ${event.eventPhase}`, 'capture')
        },

        handleBodyClick(event) {
            console.log('这是handleBodyClick');

            this.logEvent(`💻 Body捕获事件 - phase: ${event.eventPhase}`, 'capture')
        },

        handleClick(element) {
            console.log('这是handleClick', element, this.stopPropagation);

            this.logEvent(`🎯 ${element.toUpperCase()}目标事件触发`, 'target')

            if (this.stopPropagation) {
                event.stopPropagation()
                this.logEvent('🚫 已阻止事件冒泡', 'warning')
            }
        },

        // 测试事件流
        testEventFlow() {
            this.logEvent('=== 开始测试事件流 ===', 'test')
            this.logEvent(`当前配置: useCapture=${this.useCapture}, stopPropagation=${this.stopPropagation}`, 'test')

            // 模拟点击内部元素
            const innerBox = this.$refs.innerBox
            if (innerBox) {
                innerBox.click()
            }
        },

        clearLogs() {
            this.eventLogs = []
            this.logEvent('📋 日志已清空', 'info')
        }
    }
    // event.eventPhase 的可能值：
// 1: CAPTURING_PHASE    // 捕获阶段
// 2: AT_TARGET         // 目标阶段  
// 3: BUBBLING_PHASE    // 冒泡阶段
// 0: NONE              // 没有事件正在处理
    //从上到下-----window-document-body
    //      事件流三个阶段
    // 捕获阶段：从window到目标元素（红色）
    // 目标阶段：在目标元素上触发（橙色）
    // 冒泡阶段：从目标元素到window（绿色）

    // 控制事件传播
    // 阻止冒泡：控制事件在DOM树中的传播
    // event.stopPropagation()
    // 阻止默认行为：浏览器默认行为：如链接跳转、表单提交等
    // event.preventDefault()
// 立即停止传播（捕获和冒泡都停止）
// event.stopImmediatePropagation()
// 应用场景：
// 1.冒泡阶段应用：
// 事件委托 - 在父元素处理子元素事件
// parent.addEventListener('click', (e) => {
//   if (e.target.matches('.child')) {
//     // 处理子元素点击
//   }
// })
// 2.捕获阶段应用：
// 在事件到达目标之前拦截
// document.addEventListener('click', handler, { capture: true })
// event.target
// 触发事件的元素：实际被点击的元素
// 在整个事件流中保持不变
// 指向事件起源的元素
// event.currentTarget
// 当前处理事件的元素：事件监听器绑定的元素
// 随着事件传播而变化
// 指向当前正在执行处理函数的元素
// 示例演示
// document.body.addEventListener('click', function(event) {
//   console.log('target:', event.target.tagName)      // 被点击的元素（如 BUTTON）
//   console.log('currentTarget:', event.currentTarget.tagName) // 总是 BODY
// })

// 如果点击了body内的button：
// target: BUTTON
// currentTarget: BODY
}
</script>

<style scoped>
.event-flow-demo {
    padding: 20px;
    max-width: 800px;
    margin: 0 auto;
}

.flow-diagram {
    display: flex;
    justify-content: space-between;
    margin: 20px 0;
    padding: 15px;
    background: #f5f5f5;
    border-radius: 8px;
}

.phase {
    flex: 1;
    text-align: center;
    padding: 10px;
}

.capture-phase {
    color: #e74c3c;
    border-right: 2px solid #e74c3c;
}

.target-phase {
    color: #f39c12;
    border-right: 2px solid #f39c12;
}

.bubble-phase {
    color: #27ae60;
}

.demo-container {
    margin: 30px 0;
    padding: 20px;
    background: #ecf0f1;
    border-radius: 8px;
}

.outer-box {
    padding: 40px;
    background: #3498db;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.3s;
}

.outer-box:hover {
    background: #2980b9;
}

.inner-box {
    padding: 20px;
    background: #e74c3c;
    border-radius: 8px;
    color: white;
    cursor: pointer;
    transition: background 0.3s;
}

.inner-box:hover {
    background: #c0392b;
}

.control-panel {
    margin: 20px 0;
    padding: 15px;
    background: #f8f9fa;
    border-radius: 8px;
    border: 1px solid #dee2e6;
}

.control-panel .el-button,
.control-panel .el-checkbox {
    margin: 5px 10px 5px 0;
}

.log-output {
    margin-top: 20px;
}

.logs {
    max-height: 300px;
    overflow-y: auto;
    background: #2c3e50;
    color: white;
    padding: 15px;
    border-radius: 8px;
    font-family: 'Courier New', monospace;
}

.log-item {
    margin: 5px 0;
    padding: 5px;
    border-left: 3px solid transparent;
}

.log-item.capture {
    border-left-color: #e74c3c;
    color: #e74c3c;
}

.log-item.target {
    border-left-color: #f39c12;
    color: #f39c12;
}

.log-item.bubble {
    border-left-color: #27ae60;
    color: #27ae60;
}

.log-item.success {
    color: #27ae60;
}

.log-item.warning {
    color: #f39c12;
}

.log-item.test {
    color: #9b59b6;
    font-weight: bold;
}
</style>
